package com.hzzftech.watchdog.busi.core.file.repository;

import com.hzzftech.watchdog.busi.constants.BusiConstant;
import com.hzzftech.watchdog.busi.domain.KtFileRepository;
import com.hzzftech.watchdog.busi.domain.KtFileRepositoryMsg;
import com.hzzftech.watchdog.busi.domain.KtFileVersion;
import com.hzzftech.watchdog.busi.domain.KtRepositoryFile;
import com.hzzftech.watchdog.busi.service.IKtFileRepositoryMsgService;
import com.hzzftech.watchdog.busi.service.IKtFileRepositoryService;
import com.hzzftech.watchdog.busi.service.IKtFileVersionService;
import com.hzzftech.watchdog.busi.utils.FileUtils;
import com.hzzftech.watchdog.common.utils.ShiroUtils;
import com.hzzftech.watchdog.common.utils.spring.SpringUtils;

import java.io.File;
import java.util.*;

/**
 * 文件资源库解析器
 */
public class KtFileRepositoryFileParser implements FileParser {
    public static String FILE_REPOSITORY_MAGIC = "202112091619";

    private List<KtRepositoryFile> repList;

    private Long repoId;

    private IKtFileRepositoryMsgService fileService;

    private IKtFileRepositoryService fileRepositoryService;

    private IKtFileVersionService versionService;

    private String FILE_REPOSITORY_LOCATION;

    public KtFileRepositoryFileParser(IKtFileRepositoryMsgService fileService, IKtFileVersionService versionService, Long repoId, String FILE_REPOSITORY_LOCATION) {
        if (Objects.isNull(fileService) || Objects.isNull(repoId) || Objects.isNull(versionService)) {
            throw new NullPointerException("repoId、fileService和versionService不能为null");
        }
        this.repoId = repoId;
        repList = new ArrayList<>();
        this.fileService = fileService;
        this.versionService = versionService;
        this.FILE_REPOSITORY_LOCATION = FILE_REPOSITORY_LOCATION;
        fileRepositoryService = SpringUtils.getBean(IKtFileRepositoryService.class);
    }

    public static class FileWithParent {
        public Long parent;
        public File f;
    }

    @Override
    public FileParser parse(File fp) {
        List<KtFileRepositoryMsg> existsRFList = fileService.selectListByRepoId(repoId);

        // 广度优先遍历文件夹
        Queue<FileWithParent> fq = new LinkedList<>();

        FileWithParent fwp = new FileWithParent();
        fwp.parent = 0L;
        fwp.f = fp;
        fq.offer(fwp);

        StringBuilder ancestorHolder = new StringBuilder("0");
        while (!fq.isEmpty()) {
            FileWithParent poll = fq.poll();

            if (poll.f.isFile()) {
                KtFileRepositoryMsg keep = null;
                for (int i = 0;  i < existsRFList.size(); i++) {
                    if (existsRFList.get(i).getfRepoId().equals(repoId) && existsRFList.get(i).getParentId().equals(poll.parent) && existsRFList.get(i).getFileName().equals(poll.f.getName())) {
                        keep = existsRFList.get(i);
                        break;
                    }
                }
                if (Objects.isNull(keep)) {
                    UUID uuid = UUID.randomUUID();

                    KtFileRepositoryMsg file = new KtFileRepositoryMsg(
                            poll.parent,
                            ancestorHolder.toString(),
                            repoId,
                            poll.f.getName(),
                            uuid.toString(),
                            BusiConstant.FILE_TYPE_F,
                            poll.f.length(),
                            BusiConstant.FILE_DEL_NO,
                            ShiroUtils.getUserId(),
                            new Date(),
                            BusiConstant.STATUS_YES);
                    fileService.insertKtFileRepositoryMsg(file);

                    KtFileVersion version = new KtFileVersion(
                            repoId,file.getId(),uuid.toString(), BusiConstant.FILE_VERSION_ENABLE_YES,new Date(), BusiConstant.FILE_DEL_NO);

                    String source = FILE_REPOSITORY_LOCATION + getFilePath(fileService.selectKtFileRepositoryMsgById(file.getId()));

                    KtFileRepository repository = fileRepositoryService.selectKtFileRepositoryById(repoId);

                    String target =FILE_REPOSITORY_LOCATION+File.separator+"version_"+repository.getDirectory()+File.separator+uuid.toString();
                    FileUtils.copyFile(source, target);
                    versionService.insertKtFileVersion(version);

                    // 更新version版本
                    file.setEnableVersion(uuid.toString());
                    fileService.updateKtFileRepositoryMsg(file);

                } else {
                    existsRFList.remove(keep);
                }

            } else {
                KtFileRepositoryMsg keep = null;
                for (int i = 0;  i < existsRFList.size(); i++) {
                    if (existsRFList.get(i).getfRepoId().equals(repoId) && existsRFList.get(i).getParentId().equals(poll.parent) && existsRFList.get(i).getFileName().equals(poll.f.getName())) {
                        keep = existsRFList.get(i);
                        break;
                    }
                }
                UUID uuid = UUID.randomUUID();
                if (Objects.isNull(keep)) {
                    keep = new KtFileRepositoryMsg(
                            poll.parent,
                            ancestorHolder.toString(),
                            repoId,
                            poll.f.getName(),
                            uuid.toString(),
                            BusiConstant.FILE_TYPE_DIRECTORY,
                            0L,
                            BusiConstant.FILE_DEL_NO,
                            ShiroUtils.getUserId(),
                            new Date(),
                            BusiConstant.STATUS_YES);
                    fileService.insertKtFileRepositoryMsg(keep);

                } else {
                    existsRFList.remove(keep);
                }

                ancestorHolder.append(",").append(keep.getId());

                File[] chs = poll.f.listFiles(pathname -> !pathname.getName().startsWith("."));
                for (File f : chs) {
                    FileWithParent fwp1 = new FileWithParent();
                    fwp1.parent = keep.getId();
                    fwp1.f = f;
                    fq.offer(fwp1);
                }
            }
        }

        existsRFList.forEach(e -> {
            fileService.deleteKtFileRepositoryMsgById(e.getId());
            List<KtFileVersion> versions = versionService.selectKtFileVersionByRepoAndFileId(repoId, e.getId());
            for (KtFileVersion v : versions) {
                KtFileRepository repository = fileRepositoryService.selectKtFileRepositoryById(repoId);
                String target =FILE_REPOSITORY_LOCATION+File.separator+"version_"+repository.getDirectory()+File.separator+v.getVersion();
                FileUtils.delete(target);
            }
            versionService.deleteByFileId(e.getfRepoId(), e.getId());
        });

        return this;
    }

    @Override
    public List getResultList() {
        return repList;
    }

    public String getFilePath(KtFileRepositoryMsg msg){
        StringBuilder res = new StringBuilder(File.separator+msg.getFileName());
        KtFileRepositoryMsg work = msg;

        while (!work.getParentId().equals(0L)) {
            KtFileRepositoryMsg parentMsg = fileService.selectKtFileRepositoryMsgById(work.getParentId());
            res.insert(0,File.separator+ parentMsg.getFileName());
            work = parentMsg;
        }
        return res.toString();
    }
}
